<?php

namespace app\common\services\table;

use addons\gs_xsy\util\Fun;
use FormBuilder\Driver\CustomComponent;
use FormBuilder\Driver\FormComponent;
use FormBuilder\Factory\Elm;
use FormBuilder\UI\Elm\Validate;
use hiduoke\services\FormBuilder as Form;
use PhpOffice\PhpSpreadsheet\Calculation\Statistical\Distributions\F;
use think\facade\Db;
use think\helper\Str;
use think\Model;

class DataForm extends BaseTable
{
    // 表单ID
    public $id = 0;
    // 编辑数据
    public $row = null;
    // 编辑弹窗标题
    public $editTitle = '编辑';
    // 新增弹窗标题
    public $addTitle = '新增';
    // 提交地址
    public $actionUrl = '';
    // 提交方法
    public $method = 'POST';
    // 必填项字段
    public $requiredFields = [];
    // 设置表单标题
    public $titles = [];
    // 设置验证规则
    public $validates = [];
    // 设置验证错误提示
    public $messages = [];
    // 设置字段帮助
    public $helps = [];
    // 自定义表单
    public $customRules = [];
    // 过滤的字段
    public $filterFields = [];

    // 表单配置
    public $config = [];

    // 选项卡字段
    public $tabFields = [];

    // 远程搜索地址
    public $remoteUrls = [];

    // 在字段前插入
    protected $beforeFields = [];

    // 在字段后插入
    protected $afterFields = [];
    // 自定义设置的参数
    protected array $customFieldConfigs = [];
    // 联动表单
    protected array $controlFields = [];

    public function __construct(string|Model $table)
    {
        parent::__construct($table);
        $this->setId(input('id', 0));
        if (!$this->row) {
            $this->row = $this->model->findOrEmpty($this->id);
        }
        if (!$this->actionUrl) {
            $this->actionUrl = $this->getActionUrl();
        }
        $this->filterFields = [$this->model->getPk(), 'create_time', 'update_time', 'delete_time', 'plaid', 'appid', 'config'];
    }

    public function create()
    {
        $form = Form::createForm($this->actionUrl)
            ->setMethod($this->method)
            ->setTitle($this->id ? $this->editTitle : $this->addTitle)
            ->setRule($this->getRule())
            ->setConfig($this->config);
        $form = Form::getFormData($form);
        return $form;
    }


    protected function getRule($_field = null)
    {
        $rules = [];
        $Columns = $this->getColumnByFields();
        foreach ($Columns as $key => $column) {
            $field = $column['Field'];
            if ($_field && $field !== $_field) {
                continue;
            }
            if (isset($this->customRules[$field])) {
                $rules[$field] = $this->customRules[$field];
                continue;
            }

            if (!empty($this->customFieldConfigs[$field])) {
                $column = array_merge($column, $this->customFieldConfigs[$field]);
            }

            $title = $this->titles[$column['Field']] ?? $column['Title'];
            $value = $this->row[$column['Field']] ?? $column['Default'];
            $default = $column['Default'] ? [$column['Default']] : [];
            $values = $this->row[$column['Field']] ?? $default;
            $inputType = $this->getTableColumnsDataType($column);

            $rule = null;
            switch ($inputType) {
                case 'checkbox':
                    $rule = Form::$inputType($field, $title, $values);
                    break;
                case 'dkImageList':
                case 'dkFileList':
                case 'dkAudioList':
                case 'dkVideoList':
                    $rule = Form::$inputType($field, $title, $values)->limit(5);
                    break;
                case 'remoteSelects':
                    if (isset($this->remoteUrls[$field]) || isset($column['remote_url'])) {
                        $url = $column['remote_url'] ?? $this->remoteUrls[$field];
                        $rule = Form::dkSelect($field, $title, $values)->multiple(true)->remoteUrl($url)->filterable(true)->clearable(true);
                    }
                    break;
                case 'remoteSelect':
                    if (isset($this->remoteUrls[$field])) {
                        $url = $this->remoteUrls[$field];
                        $rule = Form::dkSelect($field, $title, $value)->remoteUrl($url)->filterable(true)->clearable(true);
                    }
                    break;
                case 'selects':
                    $rule = Form::select($field, $title, $values)->multiple(true)->filterable(true);
                    break;
                case 'weigh':
                    $inputType = 'number';
                    $rule = Form::$inputType($field, $title, floatval($value));
                    break;
                case 'number':
                    // 整数
                    $rule = Form::$inputType($field, $title, floatval($value));
                    break;
                // 时间戳
                case 'timestamp':
                    $rule = Form::datetime($field, $title, $value)->valueFormat('X');
                    break;
                // 日期
                case 'date':
                    if (!$value) {
                        $value = date("Y-m-d", time());
                    }
                    $rule = Form::$inputType($field, $title, $value);
                    break;
                // 兼容table的开关名称
                case 'switch':
                    $inputType = 'switches';
                default:
                    /** @var FormComponent $rule */
                    $rule = Form::$inputType($field, $title, $value);
                    break;
            }
            if (!isset($rule)) {
                continue;
            }
            // 设置禁用
            if(isset($column['disabled']) && $column['disabled']){
                $rule->disabled(true);
            }
            // 设置选项
            if (isset($column['option']) && in_array($inputType, ['checkbox', 'select', 'selects', 'radio'])) {
                $rule->options($column['option'] ?? []);
            }
            if ($inputType === 'switches' && is_int($value)) {
                // 开关
                $rule = $rule->activeValue(1)->inactiveValue(0);
            }
            // 是否必填项
            if (isset($column['required']) && $column['required']) {
                $rule->required();
            } else if (in_array($column['Field'], $this->requiredFields)) {
                //  设置字段是否必填
                $rule->required();
            }
            // 设置帮助信息
            if (isset($this->helps[$field]) || isset($column['help'])) {
                $help = $column['help'] ?? $this->helps[$field];
                $rule->effect(['help' => $help]);
            }
            // 设置验证规则
            if (isset($column['validate'])) {
                /** @var FormComponent $rule */
                $rule->validate($this->getValidateArrayByField($field, $column['validate'], $column['message'] ?? ''));
            } elseif ($this->getValidateArrayByField($field)) {
                /** @var FormComponent $rule */
                $rule->validate($this->getValidateArrayByField($field));
            }
            // 设置数据联动
            if (isset($this->controlFields[$field])) {
                $controls = $this->controlFields[$field];
                foreach ($controls as $val => $rule_fields) {
                    $control = [];
                    foreach ($rule_fields as $key => $rule_field) {
                        $control[] = $this->getRule($rule_field);
                    }
                    $rule->appendControl($val, $control);
                }
            }
            // 获取指定字段表单配置
            if ($_field && $field === $_field) {
                return $rule;
            }

            // 子页面字段判断逻辑 start
            $childValue = null;
            $childField = $this->model->childFields[$field] ?? null;
            // 多维数组方案
            if ($childField) {
                if (is_array($childField)) {
                    $param = $childField['param'] ?? $field;
                    // 判断是否有查询参数
                    $childValue = input($param);
                } else {
                    $childValue = input($field);
                }
            } else if (in_array($field, $this->model->childFields)) {
                // 数组方案
                $childValue = input($field);
            }
            // 如果有值，则设置隐藏字段
            if ($childValue !== null) {
                $rule = Form::hidden($field, $childValue);
            }
            // 子页面字段判断逻辑 end

            if (!count($this->tabFields)) {
                // 不存在选项卡
                array_push($rules, ...$this->getBeforeByFiled($column['Field']));
                $rules[$column['Field']] = $rule;
                array_push($rules, ...$this->getAfterByFiled($column['Field']));
            } else {
                $rules[$column['Field']] = $rule;
            }

        }
        // 配置了选项卡
        if (count($this->tabFields)) {
            $modelValue = 'tab_0';
            $form = Form::ElTabs()->style(['width' => '100%']);
            foreach ($this->tabFields as $key => $value) {
                $_rules = [];
                foreach ($value['fields'] as $k => $val) {
                    if (isset($rules[$val])) {
                        array_push($_rules, ...$this->getBeforeByFiled($val));
                        $_rules[] = $rules[$val];
                        array_push($_rules, ...$this->getAfterByFiled($val));
                    } else {
                        // 自定义表单
                        if (isset($this->customRules[$val])) {
                            $_rules[] = $this->customRules[$val];
                        }
                    }

                }
                $form->appendChild(
                    Form::ElTabPane()->props(['label' => $value['name'], 'name' => 'tab_' . $key])->appendChildren($_rules)
                );
                if (isset($value['default']) && $value['default']) {
                    $modelValue = 'tab_' . $key;
                }
            }
            $form->props(['modelValue' => $modelValue]);
            return [$form];
        }
        return $rules;
    }

    /**
     * 获取某字段后插入的表单
     * @param $filed
     * @return array|mixed
     */
    protected function getAfterByFiled($filed)
    {
        if (isset($this->afterFields[$filed])) {
            $after = $this->afterFields[$filed];
            if (isset($after[0])) {
                // 多维
                return $after;
            } else {
                return [$after];
            }
        }
        return [];
    }

    /**
     * 获取某字段前插入的表单
     * @param $filed
     * @return array|mixed
     */
    protected function getBeforeByFiled($filed)
    {
        if (isset($this->beforeFields[$filed])) {
            $before = $this->beforeFields[$filed];
            if (isset($before[0])) {
                // 多维
                return $before;
            } else {
                return [$before];
            }
        }
        return [];
    }

    protected function getColumnByFields()
    {
        $columns = [];
        $prefix = config('database.connections.mysql.prefix');

        $table_name = $prefix . strtolower($this->tableName);

        $query = "SHOW FULL COLUMNS FROM `{$table_name}`";

        $data = Db::query($query);

        foreach ($data as $key => $value) {
            if (in_array($value['Field'], $this->filterFields) && !in_array($value['Field'], $this->fields)) continue;
            $column = $value;
            $column['Title'] = $value['Comment'] ?: $this->fieldComment[$value['Field']] ?? $value['Field'];
            if (strpos($column['Title'], ':') !== false) {
                list($title, $values) = explode(':', $column['Title']);
                $column['Title'] = $title;
                $replaceValues = array_map(function ($item) {
                    $value = [];
                    list($value['value'], $value['label']) = explode('=', $item);
                    return $value;
                }, explode(',', $values));
                $column['option'] = $replaceValues;
            }
            $columns[$column['Field']] = $column;
        }
        // 存在用户自定义字段
        if (count($this->fields)) {
            $_columns = [];
            foreach ($this->fields as $key => $value) {
                if (isset($columns[$value])) {
                    $_columns[] = $columns[$value];
                } else if (isset($this->customRules[$value])) {
                    $_columns[] = [
                        "Field" => $value,
                        'Type'  => 'custom'
                    ];
                }
            }
            return $_columns;
        }
        return $columns;
    }

    /**
     * 获取提交地址
     * @return string
     */
    private function getActionUrl()
    {
        $rq = request();
        $path = $rq->baseUrl();
        $path = str_replace('/form', '/save', $path);
        $path = $path . '?id=' . $this->id;
        $params = $rq->request();
        unset($params['s']);
        return $path . '&' . http_build_query($params);
    }

    /**
     * 设置添加弹窗标题
     * @param string $addTitle
     * @return $this
     */
    public function setAddTitle(string $addTitle)
    {
        $this->addTitle = $addTitle;
        return $this;
    }

    /**
     * 设置提交地址
     * @param string $actionUrl
     * @return $this
     */
    public function setActionUrl(string $actionUrl)
    {
        $this->actionUrl = $actionUrl;
        return $this;
    }

    /**
     * 设置方法
     * @param string $method
     * @return $this
     */
    public function setMethod(string $method)
    {
        $this->method = $method;
        return $this;
    }

    /**
     * 设置ID
     * @param int $id
     * @return $this
     */
    public function setId(int $id)
    {
        $this->id = $id;
        return $this;
    }

    /**
     * 设置编辑弹窗标题
     * @param string $editTitle
     * @return $this
     */
    public function setEditTitle(string $editTitle)
    {
        $this->editTitle = $editTitle;
        return $this;
    }

    /**
     * 设置必填项
     * @param array $requiredFields
     * @return $this
     */
    public function setRequiredFields(array $requiredFields)
    {
        $this->requiredFields = $requiredFields;
        return $this;
    }

    /**
     * 设置必填字段
     * @param string $requiredField
     * @return $this
     */
    public function setRequiredField(string $requiredField)
    {
        $this->requiredField[] = $requiredField;
        return $this;
    }

    /**
     * 设置帮助内容
     * @param array $helps
     * @return $this
     */
    public function setHelps(array $helps)
    {
        $this->helps = $helps;
        return $this;
    }

    /**
     * 设置帮助内容
     * @param string $field
     * @param string $help
     * @return $this
     */
    public function setHelp(string $field, string $help)
    {
        $this->helps[$field] = $help;
        return $this;
    }

    /**
     * 设置表单标题
     * @param string $field
     * @param string $label
     * @return $this
     */
    public function setTitles(string $field, string $title)
    {
        $this->titles[$field] = $title;
        return $this;
    }

    /**
     * 设置验证规则
     * @param string $field
     * @param string|array $validate str,arr,num,date,int,float,object,email,enum,url,hex
     * @return $this
     */
    public function setValidates(string $field, string|array $validate)
    {
        if (is_string($validate)) {
            $validate = [$validate];
        }
        $this->validates[$field] = $validate;
        return $this;
    }

    /**
     * 设置验证错误提示
     * @param string $field
     * @param string $message
     * @return $this
     */
    public function setMessages(string $field, string $message)
    {
        $this->messages[$field] = $message;
        return $this;
    }

    /**
     * 设置自定义字段表单
     * @param array|callable $rules
     * @return $this
     */
    public function setRules($rules)
    {
        if (is_array($rules)) {
            $this->customRules = $rules;
        } else {
            $this->customRules = $rules($this->row);
        }
        return $this;
    }

    /**
     * 设置自定义表单
     * @param string $field
     * @param $rule
     * @return $this
     */
    public function setRule(string $field, $rule)
    {
        if ($rule instanceof CustomComponent) {
            $this->customRules[$field] = $rule;
        } else {
            $this->customRules[$field] = $rule($this->row);
        }
        return $this;
    }

    /**
     * 设置表单配置项
     * @param array $config 设置表单配置
     * @param string $config ['style'] 表单内style样式
     * @param bool $config ['draggable'] 是否可拖拽
     * @param bool $config ['fullscreen'] 是否全屏
     * @param string $config ['defaultWidth'] 默认宽度
     * @param string $config ['width'] 固定宽度
     * @param bool $config ['autoFullscreen'] 屏幕低于768自动全屏
     * @param string $config ['dialog'] 设置弹窗的props例如：'dialog'=>['top'=>'4vh']
     * @return $this
     */
    public function config(array $config)
    {
        $this->config = $config;
        return $this;
    }

    /**
     * 设置要使用的字段表单，并按照当前顺序显示表单
     * @param array|string $fieldList
     * @return $this
     */
    public function field(array|string $fieldList)
    {
        return parent::field($fieldList); // TODO: Change the autogenerated stub
    }

    /**
     * 设置过滤的字段
     * @param array $filterFields
     * @return $this
     */
    public function setFilterFields(array $filterFields, $type = 'add')
    {
        if ($type === 'add') {
            $this->filterFields = array_merge($this->filterFields, $filterFields);
        } else {
            $this->filterFields = $filterFields;
        }
        return $this;
    }

    /**
     * 设置过滤的字段
     * @param array $filterFields
     * @return $this
     */
    public function setFilterField(array $filterFields, $type = 'add')
    {
        return $this->setFilterFields($filterFields, $type);
    }

    /**
     * 设置选项卡字段
     * @param array $tabFields
     * @return $this
     */
    public function setTabFields(array $tabFields)
    {
        $this->tabFields = $tabFields;
        return $this;
    }

    /**
     * 设置远程搜索地址
     * @param array $remoteUrls
     * @return $this
     */
    public function setRemoteUrls(array $remoteUrls)
    {
        $this->remoteUrls = $remoteUrls;
        return $this;
    }

    /**
     * 设置插入字段后
     * @param array $afterFields
     * @return $this
     */
    public function setAfterFields(array $afterFields)
    {
        $this->afterFields = $afterFields;
        return $this;
    }

    /**
     * 设置插入字段前
     * @param array $beforeFields
     * @return $this
     */
    public function setBeforeField($field, $column)
    {
        $this->beforeFields[$field] = $column;
        return $this;
    }

    /**
     * 设置插入字段后
     * @param array $afterFields
     * @return $this
     */
    public function setAfterField($field, $column)
    {
        $this->afterFields[$field] = $column;
        return $this;
    }

    /**
     * 设置插入字段前
     * @param array $beforeFields
     * @return $this
     */
    public function setBeforeFields(array $beforeFields)
    {
        $this->beforeFields = $beforeFields;
        return $this;
    }

    public function getValidateArrayByField($field, $validates = [], $message = '')
    {
        $default_validate = ['string', 'array', 'number', 'date', 'integer', 'float', 'object', 'email', 'enum', 'url', 'hex'];
        $validates = $validates ?: ($this->validates[$field] ?? []);
        if (!$validates) {
            return [];
        }
        $validateObjs = [];
        // 验证不通过提示
        $message = $message ?: ($this->messages[$field] ?? "请输入内容");
        foreach ($validates as $key => $value) {
            if (in_array($value, $default_validate)) {
                $validate = new Validate($value, Validate::TRIGGER_CHANGE);
                $validate->message($message)->required();
                $validateObjs[] = $validate;
            }
        }
        return $validateObjs;
    }

    /**
     * 设置单个字段
     * @param string $fieldName
     * @param array $config
     * @return $this
     */
    public function setField(string $fieldName, array $config): self
    {
        if (empty($config['Field'])) {
            $config['Field'] = $fieldName;
        }
        $this->customFieldConfigs[$fieldName] = $config;
        return $this;
    }

    /**
     * 设置数据联动字段
     * Create by :  刘泓宾<514660094@qq.com>
     * @param string $field
     * @param array $controls ['值1'=>['字段'],'值2'=>['字段']]
     * @return $this
     */
    public function setControlFields(string|array $field, array $controls = [])
    {
        if (is_array($field)) {
            foreach ($field as $key => $value) {
                $this->controlFields[$key] = $value;
            }
        } else {
            $this->controlFields[$field] = $controls;
        }

        return $this;
    }
}
